supce's blog

CSS Secret 读书笔记之结构与布局(一)


自适应内部元素

如果不给一个元素指定一个具体的高度(height),这个元素就会根据内容适应高度。但是对于width怎么样才能有类似的行为呢?
首先给出一段HTML测试代码:

<p>猫,属于猫科动物,分家猫、野猫,是全世界家庭中较为广泛的宠物。家猫的祖先据推测是起源于古埃及的沙漠猫,波斯的波斯猫,已经被人类驯化了3500年(但未像狗一样完全地被驯化)。</p>
<figure>
    <img src="cat.jpg">
    <figcaption>猫咪的训练要从幼时抓起,先要摸清猫咪的脾气,然后根据需要选择不同的方式来进行训练。以下几种方式可供选用:强迫、诱导、奖励、惩罚、喊叫。</figcaption>
</figure>
<p>猫,分多种,是鼠的天敌。各地都有畜养。有黄、黑、白、灰等各种颜色;身形像狸,外貌像老虎,毛柔而齿利(有几乎无毛的品种)。以尾长腰短,目光如金银,上腭棱多的最好。身体小巧,样子招人喜爱。好奇心重。</p>

设置一些基本的样式:

figure{
    padding: 10px;
    border: 1px solid black;
    margin: auto;
}
figure > img{ max-width: inherit; }

初始的效果是这样的:

这个时候希望figure元素能够跟它所包含的图片宽度一样,而且是水平居中的。即:如何让figure的宽度让内部的图片决定。
首先想到的是浮动,给figure增加float: left;
这时候宽度虽然符合要求,但是改变了原有的布局。
如果对figure元素设置display: inline-block;,让它根据内容来决定自身的尺寸。但是元素的宽度并不是根据图片的宽度来决定的。

最后只能设置figure元素为定宽,然后对其内部的img设置max-width: 100%;,但是这就意味着放弃了响应式布局。
当然之前也用过JS来动态的设置figure宽度,但是我们可以利用CSS3的一个新关键字,轻松解决这个问题。
CSS3中为heightwidth属性定义了一min-content的关键字。这个关键字将元素的宽度设置为元素内部最大的不可断行元素的宽度(即最宽的单词,图片,或具有固定宽度的盒元素)。
为了平稳回退,可以再给元素设置一个固定的max-width值。最终代码如下:

figure{
    padding: 10px;
    border: 1px solid black;
}
figure{
    max-width: 300px;
    max-width: min-content;
    margin: auto;
}
figure > img{ max-width: inherit; }

问题轻松解决~


精准控制表格列宽

对于table有一个属性,叫作table-layout,它的默认值为auto,其行为模式被称作自定表格布局算法。也就是平时所看到的表格布局行为。
其具体的行为可以用下面这断代码来演示:
为了便于演示,先把CSS样式放前面,然后再把HTML分段。

section{
    width: 500px;
    margin: 20px;
    border: 1px dashed red;
}
table{
    margin-bottom: 20px;
    border-collapse: collapse;
    width: 100%;
}
table,tr,td{
    border: 1px solid black;
}
td.preformatted{
    white-space: pre;
    text-overflow: ellipsis;
    overflow: hidden;
}

HTML:

<section>
    <div>
        <table>
            <tr>
                <td>如果我们不</td>
                <td>指定单元格的宽度,则这些单元格就会根据它们内容的长短来分配宽度,也就是说,内容较长的单元格所能分配到的宽度也较多</td>
            </tr>
        </table>
        <table>
            <tr>
                <td>如果我们不</td>
                <td>指定单元格的宽度,则这些单元格就会根据它们内容的长短来分配宽度,也就是说,内容较长的单元格所能分配到的宽度也较多</td>
            </tr>
            <tr>
                <td>表格的每一行都会参与到列宽的计算中,而不仅是第一行</td>
                <td>注意,这个表格的列宽分配结果跟上面那个表格不同</td>
            </tr>
        </table>
        <table>
            <tr>
                <td style="width:1000px">即使我们为单元格指定了宽度,也未必会得到对应的结果。比如这个单元格宽度为1000px</td>
                <td style="width:2000px">这个单元格宽度被指定为2000px。由于外层容器不足以提供3000px,则两个单元格等比例缩小为33.3%和66.6%</td>
            </tr>
        </table>

        <table>
            <tr>
                <td>如果我们禁止文本折行,那么表格宽度也可能远远超出其容器的宽度</td>
                <td class="preformatted">而且 text-flow:ellipsis 对此也无能为力而且 text-flow:ellipsis 对此也无能为力而且 text-flow:ellipsis 对此也无能为力</td>
            </tr>
        </table>
        <table>
            <tr>
                <td>大图片或者代码块也可能会导致同样的问题</td>
                <td><img src="http://lea.verou.me/book/panoramic.jpg" /></td>
            </tr>
        </table>
    </div>
</section>

如果我们把table-layout的值设置为fixed,这时候就是利用固定表格布局算法了。在这个算法下,表格的内容不会影响单元格的宽度,它把更多的控制权交给开发者,我们设置的宽度也会起作用,同时,类似于溢出等元素行为也会接受控制,因此的表格的内容将只能影响表格的行高。


通过对比可以发现,设置fixed后,图片所在的单元行并没有根据图片的宽度来扩大自己的宽度。
如果给该单元格设置overflow: hidden;也是有效的:


满幅的背景,定宽的内容

有一种网页设计方案,特别是在电子产品的介绍页面比较流行。比如下图某手机的发布页面:

这种设计可以称作为“背景宽度满幅,内容宽度固定”。其典型的特征如下:

  • 页面中包含多个大区块,每个区块都占据了整个视口的宽度,区块的背景也各不相同。
  • 内容是定宽的,即使在不同分辨率下的宽度不一样,那也只是因为媒体查询改变了这个固定宽度的宽度值。在某些情况下,不同区块的内容也可能具有不同的宽度。

要实现这种设计风格,最常见的方法就是为每个区块准备两层元素:外层用来实现满幅的背景,内层用来实现定宽的内容,然后再通过margin: auto;实现内容的水平居中。
比如下面这个例子:
HTML:

<footer>
    <div class="wrapper">
        <!--内容部分-->
    </div>
</footer>

CSS:

footer{
    blackground: url();
}
.wrapper{
    max-width:900px;
    margin: 1em auto;
}

如果对marign: auto;有足够的了解,就会发现没必要再添加一层额外的元素。
margin: auto所产生的左右外边距实际上都等于视口宽度的一半减去内容宽度的一半,根据上面的例子,左右外边距就是:50% - 450px。这时候就可以利用我们之前用到过的calc了。
可以把上面的代码修改下:

footer{
    blackground: url();
}
.wrapper{
    max-width:900px;
    margin: 1em calc(50% - 450px);
}

我们最初的需求是能够去掉包裹内容的div元素。这时候可以稍微改变下思路,去掉div,给父元素设置padding值:

footer{
    padding: 1em; /*平稳回退*/
    padding: 1em calc(50% - 450px);
    blackground: url();
}